// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#ifndef _DATE_H_
#define _DATE_H_

#include <string>

#include "netlib/base/copyable.h"

struct tm;

namespace netlib {

///
/// Date in Gregorian calendar.
///
/// This class is immutable.
/// It's recommended to pass it by value, since it's passed in
/// register on x64.
///
class Date : Copyable {
public:
	struct YearMonthDay {
		int year_;  // [1900..2500]
		int month_; // [1..12]
		int day_;   // [1..31]
	};

	static const int kDaysPerWeek = 7;
	static const int kJulianDayOf19700101;

	///
	/// Constucts an invalid Date.
	///
	Date() : julian_day_number_(0) {}

	///
	/// Constucts a yyyy-mm-dd Date.
	///
	/// 1 <= month <= 12
	Date(int year, int month, int day);

	///
	/// Constucts a Date from Julian Day Number.
	///
	explicit Date(int julianDayNum) : julian_day_number_(julianDayNum) {}

	///
	/// Constucts a Date from struct tm
	///
	explicit Date(const struct tm& /*t*/);

	// default copy/assignment/dtor are Okay

	void Swap(Date& that) { std::swap(julian_day_number_, that.julian_day_number_); }

	bool Valid() const { return julian_day_number_ > 0; }

	///
	/// Converts to yyyy-mm-dd format.
	///
	std::string ToIsoString() const;

	struct YearMonthDay GetYearMonthDay() const;

	int Year() const { return YearMonthDay().year_; }

	int Month() const { return YearMonthDay().month_; }

	int Day() const { return YearMonthDay().day_; }

	// [0, 1, ..., 6] => [Sunday, Monday, ..., Saturday ]
	int WeekDay() const { return (julian_day_number_ + 1) % kDaysPerWeek; }

	int JulianDayNumber() const { return julian_day_number_; }

private:
	int julian_day_number_;
};

inline bool operator<(Date x, Date y) { return x.JulianDayNumber() < y.JulianDayNumber(); }

inline bool operator==(Date x, Date y) { return x.JulianDayNumber() == y.JulianDayNumber(); }

} // namespace netlib

#endif
